/*
 * Copyright 2016-2023 NXP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of NXP Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file    evkbimxrt1050_selfweld_freertos_v0.1.c
 * @brief   Application entry point.
 */
/*FreeRTOS*/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "semphr.h"

#include <stdio.h>
#include <stdlib.h>
#include "board.h"
#include "peripherals.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "MIMXRT1052.h"
#include "fsl_debug_console.h"

/*LVGL*/
#include "lvgl.h"
#include "lvgl_support.h"
#include "gui_guider.h"
#include "events_init.h"
#include "custom.h"


/*ADC*/
#include "h_adc.h"



/*SD*/
#include "ff.h"
#include "diskio.h"
#include "fsl_sd_disk.h"
#include "fsl_sd.h"
#include "semphr.h"
#include "limits.h"
#include "sdmmc_config.h"
#include "fsl_common.h"
/*RTC*/
#include "rtc_RX8010.h"
/*LAN*/
#include "fsl_phyksz8081.h"
#include "fsl_iomuxc.h"
#include "fsl_enet.h"

#include "fsl_phy.h"
#include "mqtt_freertos.h"
#include "fsl_silicon_id.h"
#include "lwip/opt.h"
#include "lwip/api.h"
#include "lwip/dhcp.h"
#include "lwip/netifapi.h"
#include "ethernetif.h"
/*user_data*/
#include "collect_data.h"
collect_data h_collect_data;
static SemaphoreHandle_t xMutex;
static char h_time[20];
/*485*/
#include "uart_qrcode.h"
#include "wit_c_sdk.h"
extern volatile bool isIdleLineDetected;
static void QRcodeTask(void *param);
static void CollectTask(void *param);
/*event*/
#include "event_groups.h"
bool start_mqtt_timer = false;

#define MQTT_TRANSMIT_TIME (0x01 << 0)
#define MQTT_TRANSMIT_LAN (0x01 << 1)


/*queue*/
#include "queue.h"
QueueHandle_t up_Queue =NULL;
/*SD*/
static bool sd_complete;
static FIL g_fileObject;
static FATFS g_fileSystem; /* File system object */
#define DEMO_TASK_GET_SEM_BLOCK_TICKS 1U
/*! @brief Task stack size. */
#define ACCESSFILE_TASK_STACK_SIZE (1024U)
/*! @brief Task stack priority. */
#define ACCESSFILE_TASK_PRIORITY (configMAX_PRIORITIES - 2U)

/*! @brief Task stack size. */
#define CARDDETECT_TASK_STACK_SIZE (1024U)
/*! @brief Task stack priority. */
#define CARDDETECT_TASK_PRIORITY (configMAX_PRIORITIES - 1U)


static char filename[12];
char s_buffer1[] = {"1,2,3,4,5,6,7,8,9\n"};
/*! @brief SD card detect flag  */
static volatile bool s_cardInserted     = false;
static volatile bool s_cardInsertStatus = false;
/*! @brief Card semaphore  */
static SemaphoreHandle_t s_CardDetectSemaphore = NULL;
/*! @brief file access task handler */
TaskHandle_t fileOperateTaskHandle;
static void FileOperateTask(void *pvParameters);
void GetFilename(void);
/*user data init*/
static TimerHandle_t timer_update_Handle =NULL; /* 软件定时器句柄 */
static void timer_update_Callback(void* parameter);


/*!
 * @brief SD card detect task.
 *
 * @param pvParameters Task parameter.
 */
static void CardDetectTask(void *pvParameters);

static FATFS g_fileSystem; /* File system object */
static status_t CheckFileSystem(void);
static void SDCARD_DetectCallBack(bool isInserted, void *userData)
{
    s_cardInsertStatus = isInserted;
    xSemaphoreGiveFromISR(s_CardDetectSemaphore, NULL);
}
static void CardDetectTask(void *pvParameters)
{
    s_CardDetectSemaphore = xSemaphoreCreateBinary();

    BOARD_SD_Config(&g_sd, SDCARD_DetectCallBack, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, NULL);

    /* SD host init function */
    if (SD_HostInit(&g_sd) == kStatus_Success)
    {
        while (true)
        {
            /* take card detect semaphore */
            if (xSemaphoreTake(s_CardDetectSemaphore, portMAX_DELAY) == pdTRUE)
            {
                if (s_cardInserted != s_cardInsertStatus)
                {
                    s_cardInserted = s_cardInsertStatus;

                    if (s_cardInserted)
                    {
                        PRINTF("\r\nCard inserted.\r\n");
                        /* power off card */
                        SD_SetCardPower(&g_sd, false);
                        /* power on the card */
                        SD_SetCardPower(&g_sd, true);
                        /* make file system */
                        if (CheckFileSystem() != kStatus_Success)
                        {
                            continue;
                        }
                        PRINTF("\r\SD init success.\r\n");
                        sd_complete = true;
                        vTaskSuspend(NULL);
                    }

                }


            }
        }
    }
    else
    {
        PRINTF("\r\nSD host init fail\r\n");
    }


}



/* TODO: insert other include files here. */
/*LVGL*/
static volatile bool s_lvgl_initialized = false;
lv_ui guider_ui;
#if LV_USE_LOG
static void print_cb(const char *buf)
{
    PRINTF("\r%s\n", buf);
}
#endif
static void LVGLTask(void *param)
{
#if LV_USE_LOG
    lv_log_register_print_cb(print_cb);
#endif

    lv_port_pre_init();
    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();

    s_lvgl_initialized = true;

    setup_ui(&guider_ui);
    events_init(&guider_ui);
//    custom_init(&guider_ui);

    for (;;)
    {
        lv_task_handler();
        vTaskDelay(5);
    }
}
AT_QUICKACCESS_SECTION_CODE(void BOARD_ReconfigFlexSpiRxBuffer(void));

/*
 * When PXP fetch images from FlexSPI flash, the default FlexSPI RX buffer
 * configuration does not meet the PXP bandwidth requirement. Reconfigure
 * here.
 */
void BOARD_ReconfigFlexSpiRxBuffer(void)
{
    uint32_t ahbcr;

    /* Disable I cache and D cache */
    if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR))
    {
        SCB_DisableICache();
    }

    if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR))
    {
        SCB_DisableDCache();
    }

    ahbcr = FLEXSPI->AHBCR;

    /* Temporarily disable prefetching while changing the buffer settings */
    FLEXSPI->AHBCR = ahbcr & ~(FLEXSPI_AHBCR_CACHABLEEN_MASK | FLEXSPI_AHBCR_PREFETCHEN_MASK);

    /* Wait for FlexSPI idle to make sure no flash data transfer. */
    while ((FLEXSPI->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) == 0U)
    {
    }

    /* Allocate half of the prefetch buffer to the core */
    FLEXSPI->AHBRXBUFCR0[0] =
        FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_MSTRID(0) | FLEXSPI_AHBRXBUFCR0_BUFSZ(0x40);

    /* Disable dedicate prefetch buffer for DMA. */
    FLEXSPI->AHBRXBUFCR0[1] =
        FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_MSTRID(1) | FLEXSPI_AHBRXBUFCR0_BUFSZ(0x00);

    /* Disable dedicate prefetch buffer for DCP. */
    FLEXSPI->AHBRXBUFCR0[2] =
        FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_MSTRID(2) | FLEXSPI_AHBRXBUFCR0_BUFSZ(0x00);

    /* Other half of the buffer for other masters incl. PXP */
    FLEXSPI->AHBRXBUFCR0[3] =
        FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_MSTRID(3) | FLEXSPI_AHBRXBUFCR0_BUFSZ(0x40);

    FLEXSPI->AHBCR = ahbcr; /* Set AHBCR back to the original value */

    /* Enable I cache and D cache */
    SCB_EnableDCache();
    SCB_EnableICache();
}

/*LAN*/
/* IP address configuration. */
/* IP address configuration. */
#ifndef configIP_ADDR0
#define configIP_ADDR0 192
#endif
#ifndef configIP_ADDR1
#define configIP_ADDR1 168
#endif
#ifndef configIP_ADDR2
#define configIP_ADDR2 1
#endif
#ifndef configIP_ADDR3
#define configIP_ADDR3 126
#endif

/* Netmask configuration. */
#ifndef configNET_MASK0
#define configNET_MASK0 255
#endif
#ifndef configNET_MASK1
#define configNET_MASK1 255
#endif
#ifndef configNET_MASK2
#define configNET_MASK2 255
#endif
#ifndef configNET_MASK3
#define configNET_MASK3 0
#endif

/* Gateway address configuration. */
#ifndef configGW_ADDR0
#define configGW_ADDR0 192
#endif
#ifndef configGW_ADDR1
#define configGW_ADDR1 168
#endif
#ifndef configGW_ADDR2
#define configGW_ADDR2 1
#endif
#ifndef configGW_ADDR3
#define configGW_ADDR3 1
#endif


/* DNS address configuration. */
#ifndef configDNS_ADDR0
#define configDNS_ADDR0 8
#endif
#ifndef configDNS_ADDR1
#define configDNS_ADDR1 8
#endif
#ifndef configDNS_ADDR2
#define configDNS_ADDR2 8
#endif
#ifndef configDNS_ADDR3
#define configDNS_ADDR3 8
#endif

/* Ethernet configuration. */
extern phy_ksz8081_resource_t g_phy_resource;
#define EXAMPLE_ENET         ENET
#define EXAMPLE_PHY_ADDRESS  0x02U
#define EXAMPLE_PHY_OPS      &phyksz8081_ops
#define EXAMPLE_PHY_RESOURCE &g_phy_resource
#define EXAMPLE_CLOCK_FREQ   CLOCK_GetFreq(kCLOCK_IpgClk)

#ifndef EXAMPLE_NETIF_INIT_FN
/*! @brief Network interface initialization function. */
#define EXAMPLE_NETIF_INIT_FN ethernetif0_init
#endif /* EXAMPLE_NETIF_INIT_FN */

/*! @brief Stack size of the temporary lwIP initialization thread. */
#define INIT_THREAD_STACKSIZE 1024

/*! @brief Priority of the temporary lwIP initialization thread. */
#define INIT_THREAD_PRIO DEFAULT_THREAD_PRIO

phy_ksz8081_resource_t g_phy_resource;

static phy_handle_t phyHandle;

/*******************************************************************************
 * Code
 ******************************************************************************/
void BOARD_InitModuleClock(void)
{
    const clock_enet_pll_config_t config = {.enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1};
    CLOCK_InitEnetPll(&config);
}

static void MDIO_Init(void)
{
    (void)CLOCK_EnableClock(s_enetClock[ENET_GetInstance(EXAMPLE_ENET)]);
    ENET_SetSMI(EXAMPLE_ENET, EXAMPLE_CLOCK_FREQ, false);
}

status_t MDIO_Write(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
{
    return ENET_MDIOWrite(EXAMPLE_ENET, phyAddr, regAddr, data);
}

status_t MDIO_Read(uint8_t phyAddr, uint8_t regAddr, uint16_t *pData)
{
    return ENET_MDIORead(EXAMPLE_ENET, phyAddr, regAddr, pData);
}
static void stack_init(void *arg)
{
    static struct netif netif;
    ethernetif_config_t enet_config = {
        .phyHandle   = &phyHandle,
        .phyAddr     = EXAMPLE_PHY_ADDRESS,
        .phyOps      = EXAMPLE_PHY_OPS,
        .phyResource = EXAMPLE_PHY_RESOURCE,
        .srcClockHz  = EXAMPLE_CLOCK_FREQ,
    };
    ip4_addr_t fsl_netif0_ipaddr, fsl_netif0_netmask, fsl_netif0_gw;
    LWIP_UNUSED_ARG(arg);

    /* Set MAC address. */
#ifdef configMAC_ADDR
    enet_config.macAddress = configMAC_ADDR,
#else
    (void)SILICONID_ConvertToMacAddr(&enet_config.macAddress);
#endif
//    IP4_ADDR(&fsl_netif0_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);
//    IP4_ADDR(&fsl_netif0_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3);
//    IP4_ADDR(&fsl_netif0_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);
//
//    tcpip_init(NULL, NULL);
//    netifapi_netif_add(&netif,  &fsl_netif0_ipaddr, &fsl_netif0_netmask,  &fsl_netif0_gw, &enet_config, EXAMPLE_NETIF_INIT_FN, tcpip_input);
//    netifapi_netif_set_default(&netif);
//    netifapi_netif_set_up(&netif);



    tcpip_init(NULL, NULL);

    netifapi_netif_add(&netif, NULL, NULL, NULL, &enet_config, EXAMPLE_NETIF_INIT_FN, tcpip_input);
    netifapi_netif_set_default(&netif);
    netifapi_netif_set_up(&netif);

    netifapi_dhcp_start(&netif);
    PRINTF("\r\n************************************************\r\n");
    PRINTF(" MQTT client example\r\n");
    PRINTF("************************************************\r\n");

    while (ethernetif_wait_linkup(&netif, 5000) != ERR_OK)
    {
    	/*
    	 * 一开始就未连接，网络中断，网络标志位
    	 */
        PRINTF("PHY Auto-negotiation failed. Please check the cable connection and link partner setting.\r\n");
    }

    /* Wait for address from DHCP */

    PRINTF("Getting IP address from DHCP...\r\n");

    (void)ethernetif_wait_ipv4_valid(&netif, ETHERNETIF_WAIT_FOREVER);


//
    mqtt_freertos_run_thread(&netif);

    vTaskDelete(NULL);
}

static void timeTask(void *pvParameters);
/*
 * @brief   Application entry point.
 */

int main(void) {

	gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
	sd_complete = false;
    BaseType_t lv_task;
    BaseType_t QRcode_task;
    BaseType_t uart485_task;
//    BaseType_t e_task;
    BaseType_t sd_task;
    BaseType_t time_task;
    BaseType_t uart_task;
    // 互斥锁定义


    /* Init board hardware. */
    /* Set the eLCDIF read_qos priority high, to make sure eLCDIF
     * can fetch data in time when PXP is used.
     */
    *((volatile uint32_t *)0x41044100) = 5;

    /* Init board hardware. */
    BOARD_ConfigMPU();
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
//    BOARD_InitBootPeripherals();
#ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL
    /* Init FSL debug console. */
    BOARD_InitDebugConsole();
#endif
    BOARD_InitModuleClock();


    PRINTF("Hello World\n");

    IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true);


//    GPIO_PinInit(GPIO1, 3, &gpio_config);
//    GPIO_PinInit(GPIO1, 10, &gpio_config);
    GPIO_PinInit(GPIO1, 9, &gpio_config);
    GPIO_PinInit(GPIO1, 10, &gpio_config);

    GPIO_WritePinOutput(GPIO1, 10, 1);
//   	GPIO_WritePinOutput(GPIO1, 3, 0);
   	GPIO_WritePinOutput(GPIO1, 9, 0);
   	SDK_DelayAtLeastUs(10000, CLOCK_GetFreq(kCLOCK_CpuClk));
//    GPIO_WritePinOutput(GPIO1, 3, 1);
    GPIO_WritePinOutput(GPIO1, 9, 1);

    MDIO_Init();
    g_phy_resource.read  = MDIO_Read;
    g_phy_resource.write = MDIO_Write;

//
    adc_init();

    Uartqrcode_init();



    wit_init();

    init_collect_data(&h_collect_data);


    xMutex = xSemaphoreCreateMutex();
    if(NULL != xMutex)
        PRINTF("MuxSem_Handle互斥量创建成功!\r\n");

//    Internet_Event_Handle = xEventGroupCreate();
//    if (NULL != Internet_Event_Handle)
//    	printf("Event_Handle 事件创建成功!\r\n");


     timer_update_Handle=xTimerCreate((const char*)"updateTimer",
     							(TickType_t)800,/*定时器周期 1000(tick) */
      							(UBaseType_t)pdTRUE,/* 周期模式 */
      							(void*)1,/*为每个计时器分配一个索引的唯一 ID */
      							(TimerCallbackFunction_t)timer_update_Callback);

     if (timer_update_Handle != NULL) {
     	xTimerStart(timer_update_Handle,0); //开启周期定时器
     }


    QRcode_task = xTaskCreate(QRcodeTask, "QRcodeTask", configMINIMAL_STACK_SIZE + 800, NULL, tskIDLE_PRIORITY + 5, NULL);

	if (pdPASS != QRcode_task)
	{
		PRINTF("Failed to create collect task");
		while (1)
			;
	}

	uart485_task = xTaskCreate(CollectTask, "CollectTask", configMINIMAL_STACK_SIZE + 800, NULL, tskIDLE_PRIORITY + 6, NULL);

	if (pdPASS != uart485_task)
	{
		PRINTF("Failed to create collect task");
		while (1)
			;
	}

    /* Initialize lwIP from thread */
    if (sys_thread_new("main", stack_init, NULL, INIT_THREAD_STACKSIZE, tskIDLE_PRIORITY + 8) == NULL)
    {
        LWIP_ASSERT("main(): Task creation failed.", 0);
    }

    lv_task = xTaskCreate(LVGLTask, "lvgl", configMINIMAL_STACK_SIZE + 800, NULL, tskIDLE_PRIORITY + 4, NULL);

    if (pdPASS != lv_task)
    {
        PRINTF("Failed to create lvgl task");
        while (1)
            ;
    }

    sd_task = xTaskCreate(CardDetectTask, "CardDetectTask",1024, NULL,  tskIDLE_PRIORITY + 7, NULL);
    if (pdPASS != sd_task)
    {
        PRINTF("Failed to create sd task");
        while (1)
            ;
    }
//由于和lvgl共用i2c通信，任务优先级要低于lvgl
    time_task = xTaskCreate(timeTask, "timeTask",configMINIMAL_STACK_SIZE + 800, NULL, tskIDLE_PRIORITY + 3, NULL);
    if (pdPASS != time_task)
    {
        PRINTF("Failed to create time task");
        while (1)
            ;
    }

    vTaskStartScheduler();

    for (;;)
    {

    } /* should never get here */
}
/*!
 * @brief Malloc failed hook.
 */
void vApplicationMallocFailedHook(void)
{
    PRINTF("Malloc failed. Increase the heap size.");

    for (;;)
        ;
}

/*!
 * @brief FreeRTOS tick hook.
 */
void vApplicationTickHook(void)
{
    if (s_lvgl_initialized)
    {
        lv_tick_inc(5);
    }
}

/*!
 * @brief Stack overflow hook.
 */
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
    (void)pcTaskName;
    (void)xTask;

    for (;;)
        ;
}
static status_t CheckFileSystem(void)
{
    FRESULT error;
    const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'};
    BYTE work[FF_MAX_SS];

    if (f_mount(&g_fileSystem, driverNumberBuffer, 0U))
    {
        PRINTF("Mount volume failed.\r\n");
        return kStatus_Fail;
    }

#if (FF_FS_RPATH >= 2U)
    error = f_chdrive((char const *)&driverNumberBuffer[0U]);
    if (error)
    {
        PRINTF("Change drive failed.\r\n");
        return kStatus_Fail;
    }
#endif

#if FF_USE_MKFS
    PRINTF("\r\nMake file system......The time may be long if the card capacity is big.\r\n");
    if (f_mkfs(driverNumberBuffer, 0, work, sizeof work))
    {
        PRINTF("Make file system failed.\r\n");
        return kStatus_Fail;
    }
#endif /* FF_USE_MKFS */


    return kStatus_Success;
}

static void timeTask(void *pvParameters)
{
	BaseType_t xReturn = pdPASS;
	uint8_t value_year_h=0;
	uint8_t value_year_l=0;
	uint8_t value_month_h=0;
	uint8_t value_month_l=0;
	uint8_t value_day_h=0;
	uint8_t value_day_l=0;
	uint8_t value_hour_h=0;
	uint8_t value_hour_l=0;
	uint8_t value_minutes_h=0;
	uint8_t value_minutes_l=0;
	uint8_t value_sec_h=0;
	uint8_t value_sec_l=0;

    while(1)
    {
        rx8010_get_time(value_year_h,value_year_l,value_month_h,value_month_l,value_day_h,value_day_l,value_hour_h,value_hour_l,value_minutes_h,value_minutes_l,value_sec_h,value_sec_l);

	    sprintf(filename, "20%d%d%d%d%d%d.csv",value_year_h,value_year_l,value_month_h,value_month_l,value_day_h,value_day_l);
        sprintf(h_time,"20%d%d-%d%d-%d%d  %d%d:%d%d:%d%d",value_year_h,value_year_l,value_month_h,value_month_l,value_day_h,value_day_l,value_hour_h,value_hour_l,value_minutes_h,value_minutes_l,value_sec_h,value_sec_l);

//        PRINTF("time file name is :%s\r\n",filename);
//        PRINTF("time is :%s\r\n",h_time);

        xReturn = xSemaphoreTake(xMutex,portMAX_DELAY);
		update_collect_data(&h_collect_data,21,h_time,NULL);
        xReturn = xSemaphoreGive(xMutex);

        vTaskDelay(1000);
    }
	
}
void substring(char *dest, const char *src, size_t start, size_t len) {
    // 确保start不会超过src的长度
    if (start >= strlen(src)) {
        dest[0] = '\0';
        return;
    }

    // 计算结束位置，确保不会超过src的末尾
    size_t end = start + len;
    if (end > strlen(src)) {
        end = strlen(src);
    }

    // 复制子字符串到dest
    strncpy(dest, src + start, end - start);
    dest[end - start] = '\0'; // 确保dest是一个有效的C字符串
}
static void QRcodeTask(void *param)
{
	uint8_t buffer[100];
	char substr[12];
	memset(buffer,'\0',sizeof(buffer));
	while(1)
	{
		Uartqrcode_Read(buffer);

		/***********h_test******************/

//		update_collect_data(&h_collect_data,7,"123456789123",NULL);
//
//		update_collect_data(&h_collect_data,10,"F1",NULL);
//
//		update_collect_data(&h_collect_data,9,"12345678912345678",NULL);
		/***********end******************/
		switch(buffer[0])
		{
			case 58:
			{
				if(buffer[1] == 69)
				{
				    // 截取从索引1开始，长度为12的字符串，设备id,E的十进制编码是69
					substring(substr, buffer, 1, 12);
					update_collect_data(&h_collect_data,7,substr,NULL);
					memset(buffer,'\0',sizeof(buffer));
					break;

				}
				else if(buffer[1] == 58)
				{
					// 截取从索引2开始，长度为2的子字符串,焊层
					substring(substr, buffer, 2, 3);
					update_collect_data(&h_collect_data,10,substr,NULL);
					memset(buffer,'\0',sizeof(buffer));
					break;
				}
				else if(buffer[5] == 45)
				{
					// 截取从索引2开始，长度为2的子字符串,人员
					substring(substr, buffer, 1, 14);
					update_collect_data(&h_collect_data,9,substr,NULL);
					memset(buffer,'\0',sizeof(buffer));
					break;
				}
				break;
			 }
			default:
				break;
		}
		if(buffer[4] == '-' && strlen(buffer) > 10 && strlen(buffer) < 30)
		{
			PRINTF("QRsize:%d\r\n",strlen(buffer));
			// 截取从索引0开始，长度为26的子字符串,焊口编号
//			substring(substr, buffer, 0, 26);
			update_collect_data(&h_collect_data,8,buffer,NULL);
			memset(buffer,'\0',sizeof(buffer));
		}
		vTaskDelay(1000);
	}
}

static void CollectTask(void *param)
{

	uint32_t speed = 0;
	uint32_t voltage = 0;
	uint32_t current = 0;
	uint32_t wire_speed = 0;

    while(1)
    {

        voltage = read_witV_data();
//        voltage = 100;//h_test
        update_collect_data(&h_collect_data,15,NULL,voltage);
        vTaskDelay(200);
        current = read_witC_data();
//        current = 88;//h_test
        update_collect_data(&h_collect_data,16,NULL,current);
        vTaskDelay(200);
        wire_speed = read_witR_data();
//        wire_speed = 77;//h_test
        update_collect_data(&h_collect_data,17,NULL,wire_speed);
        vTaskDelay(200);
    	speed = read_WitA_data();
//    	speed = 66;//h_test
        update_collect_data(&h_collect_data,18,NULL,speed);
    	vTaskDelay(400);
    }

}


//定时器1回调(800ms,预留200ms处理任务)
static void timer_update_Callback(void* parameter)
{
 	TickType_t tick_num1;

	tick_num1 = xTaskGetTickCount(); /* 获取滴答定时器的计数值 */


/************adc采样电压电流，此版本只支持串口采集**************/
//	//更新电压电流
//	float voltage = 0.00;
//	float current = 0.00;
//
//	voltage = read_Vadc();
//	current = read_Cadc();
//
//	uint32_t voltage_int = 0;
//	uint32_t current_int = 0;
//
//	voltage_int = voltage * 1000;
//	current_int = current * 1000;
//
//
//	update_collect_data(&h_collect_data,15,NULL,voltage_int);
//	update_collect_data(&h_collect_data,16,NULL,current_int);
/******************end****************/
	start_mqtt_timer = true;


//file write
	FRESULT error;
	UINT bw;
	char file_buffer[200];
	insect_file_data(&h_collect_data,file_buffer);

//	PRINTF("file_buffer:%d.\r\n",strlen(file_buffer));
	if(sd_complete == true)
	{
		//Open file
		error = f_open(&g_fileObject, _T(filename), FA_WRITE);
		if (error)
		{
			if (error == FR_EXIST)
			{
				PRINTF("File exists.\r\n");
			}
			/* if file not exist, creat a new file */
			else if (error == FR_NO_FILE)
			{
				if (f_open(&g_fileObject, _T(filename), (FA_WRITE | FA_CREATE_NEW)) != FR_OK)
				{
					PRINTF("Create file failed.\r\n");
				}
			}
			else
			{
				PRINTF("Open file failed.\r\n");
			}
		}
		//chiose last sign
		if (f_lseek(&g_fileObject,f_size(&g_fileObject)) != FR_OK)
		{
			PRINTF("lseek file failed.\r\n");
		}
		//write file data
		error = f_write(&g_fileObject, file_buffer, strlen(file_buffer), &bw);
		if ((error) || (bw != strlen(file_buffer)))
		{
			PRINTF("Write file failed.\r\n");
		}

		f_close(&g_fileObject);

	}
	else
	{
		 PRINTF("file system start failed!.\r\n");
	}

//	// 进入临界区
//	taskENTER_CRITICAL();
//
//	// 访问共享资源
//
//	// 离开临界区
//	taskEXIT_CRITICAL();
	//upgrade window
	//更新时间
	lv_event_send(guider_ui.screenHome_labeldate, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_collect_time);
	//更新设备编号
	lv_event_send(guider_ui.screenHome_label_1, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_device_id);
	//更新人员编号
	lv_event_send(guider_ui.screenHome_label_2, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_person_id);
	//更新焊口编号
	lv_event_send(guider_ui.screenHome_label_3, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_id);//weld_id
	//更新方向
	lv_event_send(guider_ui.screenHome_label_4, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_direction);
	//更新焊层
	lv_event_send(guider_ui.screenHome_label_5, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_layer);
	//更新角度
	lv_event_send(guider_ui.screenHome_label_7, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_angle);
	//更新电压
	lv_event_send(guider_ui.screenHome_label_8, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_voltage);
	//更新电流
	lv_event_send(guider_ui.screenHome_label_6, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_current);
	//更新焊接速度
	lv_event_send(guider_ui.screenHome_label_9, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_speed);
	//更新送丝速度
	lv_event_send(guider_ui.screenHome_label_10, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_wire_speed);
	//更新热输入
	lv_event_send(guider_ui.screenHome_label_11, LV_EVENT_VALUE_CHANGED, h_collect_data.weld_heat_energy);


/****************end******************/
}
